package cn.ahaoweb.drule.core;

import cn.ahaoweb.drule.core.handler.PostExecuteHandler;
import cn.ahaoweb.drule.core.handler.PreExecuteHandler;
import cn.ahaoweb.drule.core.handler.RuleExecuteExceptionHandler;
import cn.ahaoweb.drule.core.listener.DefaultRuleExecuteListener;
import cn.ahaoweb.drule.core.listener.FiredRuleExecuteListener;
import cn.ahaoweb.drule.core.listener.RuleExecuteListener;
import org.kie.api.event.rule.AgendaEventListener;
import org.kie.api.runtime.KieSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Name: RuleSessionImpl
 * @Description:
 * @Author: wangzhonghao
 * @Date: 2025/2/13 15:24
 */
public class RuleSessionImpl implements RuleSession {

    private static final Logger log = LoggerFactory.getLogger(RuleSessionImpl.class);

    // 所属规则服务
    protected RuleService ruleService;

    // 全局变量
    protected Map<String, Object> globals = new HashMap<>();

    // 规则执行过程的监听器
    protected List<AgendaEventListener> listeners = new ArrayList<>();

    // 前置处理器
    protected List<PreExecuteHandler> preExecuteHandlers = new ArrayList<>();

    // 后置处理器
    protected List<PostExecuteHandler> postExecuteHandlers = new ArrayList<>();

    // 执行异常处理器
    protected RuleExecuteExceptionHandler ruleExecuteExceptionHandler;

    public RuleSessionImpl(RuleService ruleService) {
        this.ruleService = ruleService;
        init();
    }

    /**
     * 获取所属的规则服务。
     *
     * @return
     */
    public RuleService getRuleService() {
        return ruleService;
    }

    @Override
    public void init() {
        addInitListeners();
    }


    /**
     * 添加初始化监听器
     */
    protected void addInitListeners() {
        addListener(FiredRuleExecuteListener.DEFAULT);
    }

    public RuleSession addGlobal(String identify, Object value) {
        this.globals.put(identify, value);
        return this;
    }

    public Map<String, Object> getGlobals() {
        return globals;
    }

    public RuleSession addListener(RuleExecuteListener ruleExecuteListener) {
        return addAgendaEventListener(new DefaultRuleExecuteListener(null, ruleExecuteListener));
    }

    public RuleSession addAgendaEventListener(AgendaEventListener agendaEventListener) {
        if (!this.listeners.contains(agendaEventListener)) {
            this.listeners.add(agendaEventListener);
        }
        return this;
    }

    public List<AgendaEventListener> getListeners() {
        return listeners;
    }

    public RuleSession addPreExecuteHandler(PreExecuteHandler preExecuteHandler) {
        if (!this.preExecuteHandlers.contains(preExecuteHandler)) {
            this.preExecuteHandlers.add(preExecuteHandler);
        }
        return this;
    }

    public List<PreExecuteHandler> getPreExecuteHandlers() {
        return preExecuteHandlers;
    }

    public RuleSession addPostExecuteHandler(PostExecuteHandler postExecuteHandler) {
        if (!this.postExecuteHandlers.contains(postExecuteHandler)) {
            this.postExecuteHandlers.add(postExecuteHandler);
        }
        return this;
    }

    public List<PostExecuteHandler> getPostExecuteHandlers() {
        return postExecuteHandlers;
    }

    @Override
    public RuleSession executeExceptionHandler(RuleExecuteExceptionHandler executeExceptionHandler) {
        this.ruleExecuteExceptionHandler = executeExceptionHandler;
        return this;
    }

    public void execute(FactInfo factInfo) {
        try {
            doExecute(factInfo);
        } catch (RuntimeException exception) {
            handlerException(exception, factInfo);
        } finally {
            exit(factInfo);
        }
    }

    /**
     * 异常处理器
     * <p>
     * 当执行过程中发生异常时，该方法会被调用。
     *
     * @param e        抛出的异常对象
     * @param factInfo 当前执行的事实信息
     * @return 返回处理后的FactInfo对象
     * @throws RuntimeException 抛出原始异常
     */
    @Override
    public void handlerException(RuntimeException e, FactInfo factInfo) {
        if (ruleExecuteExceptionHandler == null) {
            // 设置异常
            factInfo.setError(true);
            throw e;
        }
        // 交给异常处理器处理
        ruleExecuteExceptionHandler.handleException(e, this, factInfo);
    }

    /**
     * 执行规则逻辑的主要方法
     *
     * @param factInfo 包含规则执行所需信息的事实信息对象
     */
    protected void doExecute(FactInfo factInfo) {
        enter(factInfo);
        // 前置处理
        if (preExecuteHandlers != null && !preExecuteHandlers.isEmpty()) {
            for (PreExecuteHandler preExecuteHandler : preExecuteHandlers) {
                preExecuteHandler.preHandler(factInfo);
                if (preExecuteHandler.exit()) {
                    return;
                }
            }
        }
        afterPreHandlers(factInfo);
        // 开始执行
        KieSessionWrapper session = getSession();
        fireRule(factInfo, session);
        afterExecuted(factInfo);
        // 后置处理
        if (postExecuteHandlers != null && !postExecuteHandlers.isEmpty()) {
            for (PostExecuteHandler postExecuteHandler : postExecuteHandlers) {
                postExecuteHandler.postHandler(factInfo);
                if (postExecuteHandler.exit()) {
                    return;
                }
            }
        }
        afterPostHandlers(factInfo);
        session.destroy();
    }

    protected void fireRule(FactInfo factInfo, KieSessionWrapper session) {
        KieSession kieSession = session.getKieSession();
        if (listeners != null && !listeners.isEmpty()) {
            for (AgendaEventListener listener : listeners) {
                if (listener instanceof DefaultRuleExecuteListener) {
                    DefaultRuleExecuteListener defaultRuleExecuteListener = (DefaultRuleExecuteListener) listener;
                    if (!defaultRuleExecuteListener.singleton()) {
                        try {
                            RuleExecuteListener ruleExecuteListener = defaultRuleExecuteListener.getRuleExecuteListener();
                            defaultRuleExecuteListener.setRuleExecuteListener(ruleExecuteListener.getClass().newInstance());
                        } catch (InstantiationException e) {
                            throw new RuntimeException(e);
                        } catch (IllegalAccessException e) {
                            throw new RuntimeException(e);
                        }
                    }
                    defaultRuleExecuteListener.setFactInfo(factInfo);
                    kieSession.addEventListener(defaultRuleExecuteListener);
                } else {
                    kieSession.addEventListener(listener);
                }
            }
        }
        kieSession.insert(factInfo.getInput());
        Object outputInstance = factInfo.getOutputInstance();
        if (outputInstance != null) {
            globals.put(factInfo.getOutputName(), outputInstance);
        }
        if (globals != null && !globals.isEmpty()) {
            for (Map.Entry<String, Object> global : globals.entrySet()) {
                if (global.getKey() != null && global.getValue() != null) {
                    kieSession.setGlobal(global.getKey(), global.getValue());
                }
            }
        }
        kieSession.fireAllRules();
    }

    /**
     * 进入执行方法时调用
     *
     * @param factInfo
     */
    protected void enter(FactInfo factInfo) {
    }

    /**
     * 前置处理器执行后
     *
     * @param factInfo
     */
    protected void afterPreHandlers(FactInfo factInfo) {
    }

    /**
     * 规则执行后
     *
     * @param factInfo
     */
    protected void afterExecuted(FactInfo factInfo) {
    }

    /**
     * 后置处理器执行后
     *
     * @param factInfo
     */
    protected void afterPostHandlers(FactInfo factInfo) {
    }

    /**
     * 退出执行
     *
     * @param factInfo
     */
    protected void exit(FactInfo factInfo) {
    }

    protected KieSessionWrapper getSession() {
        KieSessionWrapper kieSessionWrapper = new KieSessionWrapper(ruleService.getKieBase().newKieSession());
        return kieSessionWrapper;
    }

}
